﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace Gonte.Desktop.ExtJs
{
    /// <summary>
    /// Adapts the JSON record returned from the server to a format understood by extjs
    /// </summary>
    public class Envelope<T>
    {
        #region Constructors

        public Envelope(Func<Tuple<bool, string>> sessionVerifier = null)
        {
            count = -1;
            success = true;
            msg = string.Empty;
            this.sessionVerifier = sessionVerifier;
            TraceSource = new TraceSource("ExtJsEnvelope");
        }

        #endregion

        #region Properties

        /// <summary>
        /// Whether the operation succeeded or not
        /// </summary>
        public bool success { get; set; }

        /// <summary>
        /// The record returned by the server
        /// </summary>
        public T data { get; set; }

        /// <summary>
        /// The message to be shown in the alert box
        /// </summary>
        public string msg { get; set; }

        /// <summary>
        /// The number of rows retrieved. It has a setter to set it to the whole set when paging
        /// </summary>
        public int count { get; set; }

        public Func<Tuple<bool, string>> sessionVerifier { get; set; }

        /// <summary>
        /// The trace source to log the events to
        /// </summary>
        public static TraceSource TraceSource { get; set; }

        #endregion

        #region Methods

        public Envelope<T> Process(Func<Envelope<T>, T> action)
        {
            try
            {
                if (sessionVerifier != null)
                {
                    Tuple<bool, string> res = sessionVerifier();

                    if (!res.Item1)
                    {
                        msg = res.Item2;
                        success = false;
                        return this;
                    }
                }

                data = action(this);
                SetCount();
            }
            catch (Exception ex)
            {
                success = false;
                msg = ex.Message;

                TraceSource.TraceEvent(TraceEventType.Error, 0, "{0} {1}", ex.Message, ex.StackTrace);
            }

            return this;
        }

        private void SetCount()
        {
            if (count > -1) // It was manually set
            {
                return;
            }

            if (data == null)
            {
                count = 0;
                return;
            }

            if (data is IEnumerable<object>)
            {
                count = ((IEnumerable<object>)data).Count();
            }
            else
            {
                count = 1; // Single object
            }
        }

        #endregion

        public string ToJson()
        {
            StringBuilder builder = new StringBuilder();

            builder.Append(@"{""success"":");
            builder.Append(JsonConverter.Convert(success));

            builder.Append(@",""count"":");
            builder.Append(JsonConverter.Convert(count));

            builder.Append(@",""msg"":");
            builder.Append(JsonConverter.Convert(msg));

            builder.Append(@",""data"":");

            if (data.IsDefault())
            {
                builder.Append(@"null");
            }
            else
            {
                builder.Append(data);
            }

            builder.Append("}");

            return builder.ToString();
        }
    }
}
